package com.example.teesystem.controller;

import com.example.teesystem.common.Permission.PermissionCheck;
import com.example.teesystem.common.cache.CourseCache;
import com.example.teesystem.common.cache.UserCache;
import com.example.teesystem.common.exception.CustomException;
import com.example.teesystem.common.utils.FileUtil;
import com.example.teesystem.common.utils.PermissionUtil;
import com.example.teesystem.common.utils.Response;
import com.example.teesystem.common.utils.ResultCode;
import com.example.teesystem.common.valid.MapContains;
import com.example.teesystem.common.valid.ValidErrorMessage;
import com.example.teesystem.entity.Course;
import com.example.teesystem.entity.vo.*;
import com.example.teesystem.entity.vo.assistant.AssistantResponseVo;
import com.example.teesystem.entity.vo.course.CourseResponseVo;
import com.example.teesystem.entity.vo.course.CourseSelectVo;
import com.example.teesystem.entity.vo.course.CourseUpdateVo;
import com.example.teesystem.entity.vo.course.CourseUploadVo;
import com.example.teesystem.entity.vo.preCourse.PreCourseInsert;
import com.example.teesystem.entity.vo.preCourseScore.PreCourseScoreInsert;
import com.example.teesystem.entity.vo.preCourseScore.ScoreInsert;
import com.example.teesystem.filter.MyHandlerInterceptor;
import com.example.teesystem.mapper.AssistantMapper;
import com.example.teesystem.service.AssistantService;
import com.example.teesystem.service.CourseService;
import com.example.teesystem.service.PreCourseScoreService;
import com.example.teesystem.service.PreCourseService;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.validation.Valid;
import java.util.List;
import java.util.Map;

import static com.example.teesystem.common.utils.FileUtil.SUFFIX;

@RestController
@RequestMapping(value = "/tee/course",produces = "application/json; charset=utf-8")
@RequiredArgsConstructor
@Validated
public class CourseController {
    private final CourseService courseService;
    private final AssistantService assistantService;
    private final PreCourseService preCourseService;
    private final PreCourseScoreService preCourseScoreService;

    /**
     * 添加一门课程
     * @param courseUploadVo 课程
     * @return
     */
    @PostMapping("/add")
    public Response addCourse(@Valid @RequestBody(required = false) CourseUploadVo courseUploadVo) {
        if(courseService.addCourse(courseUploadVo)) {
            return Response.ok();
        } else {
            throw new CustomException(ResultCode.ADD_INFO_FAIL);
        }
    }
    
    /**
     * 更新课程信息
     * @param courseUpdateVo 课程
     * @return
     */
    @PostMapping("/update")
    @PermissionCheck(PermissionUtil.COURSE_INFO_EDIT)
    public Response updateCourse(@Valid @RequestBody(required = false) CourseUpdateVo courseUpdateVo) {
        if(courseService.updateCourse(courseUpdateVo)) {
            return Response.ok();
        } else {
            throw new CustomException(ResultCode.UPDATE_INFO_FAIL);
        }
    }
    
    /**
     * 分页获取课程列表
     * @param pageRequestVo 分页
     * @return
     */
    @PostMapping("/getCourses")
    public Response getCourses(@Valid @RequestBody PageRequestVo pageRequestVo) {
        if(!PermissionUtil.isManager()){
            return Response.error(ResultCode.NO_PERMISSION);
        }
        return Response.ok(courseService.getCourses(pageRequestVo.getCur(), pageRequestVo.getSize()));
    }
    
    /**
     * 根据关键字检索课程，并分页给出信息
     * @param courseSelectVo 可传递关键字有 name、teacher，必须传递 cur 和 size
     * @return
     */
    @PostMapping("/getCourseByConditions")
    public Response getCourseByConditions(@Valid @RequestBody(required = false) CourseSelectVo courseSelectVo) {
        if(!PermissionUtil.isManager()){
            return Response.error(ResultCode.NO_PERMISSION);
        }
        PageResponseVo<CourseResponseVo> pageCourses = courseService.getCourseByConditions(courseSelectVo);
        if(!pageCourses.getRecords().isEmpty()) {
            return Response.ok(pageCourses);
        } else {
            throw new CustomException(ResultCode.GET_INFO_FAIL);
        }
    }
    
    /**
     * 获取我开设的课程
     * @return
     */
    @PostMapping("/getMyCourse")
    public Response getMyCourse() {
        List<CourseResponseVo> result = courseService.getCourseByUid(MyHandlerInterceptor.getUid());
        return Response.ok(result);
    }

    /**
     * 获取自身管理的课程
     * @return
     */
    @PostMapping("/getMyManageCourses")
    public Response getMyManageCourses() {
        List<CourseResponseVo> result = courseService.getCourseByAssistantId(MyHandlerInterceptor.getUid());
        return Response.ok(result);
    }

    
    /**
     * 根据 id 获取课程
     * @param map 包含课程 id
     * @return
     */
    @PostMapping("/getCourseById")
    public Response getCourseById(
            @MapContains(keys = {"id"}, message = ValidErrorMessage.COURSE_ID_VALID_FAIL)
            @RequestBody Map<String, Integer> map) {
        Integer courseId = map.get("id");
        return Response.ok(courseService.getCourseById(courseId))
                .put("assistant", assistantService.getAssistantNamesByCourseId(courseId));
    }
    
    /**
     * 学生获取自己加入的课程
     * @return
     */
    @PostMapping("/getCourseByStudentId")
    public Response getCourseByStudentId() {
        int studentId = MyHandlerInterceptor.getUid();
        List<CourseResponseVo> courses = courseService.getCourseByStudentId(studentId);
        return Response.ok(courses);
    }
    
    /**
     * 根据 id 删除课程
     * @param map 包含课程 id
     * @return
     */
    @PostMapping("/delete")
    @PermissionCheck(PermissionUtil.COURSE_INFO_EDIT)
    public Response delete(
            @MapContains(keys = {"id"}, message = ValidErrorMessage.COURSE_ID_VALID_FAIL)
            @RequestBody Map<String, Integer> map) {
        if(!PermissionUtil.permissionCheck(MyHandlerInterceptor.getUid(),PermissionUtil.COURSE_INFO_EDIT,map.get("id"))) {
            return Response.error(ResultCode.NO_PERMISSION);
        }
        if(courseService.delete(map.get("id"))) {
            return Response.ok();
        } else {
            throw new CustomException(ResultCode.DELETE_INFO_FAIL);
        }
    }
    
    /**
     * 上传图片
     * @param id 课程 id
     * @param files 课程图片
     * @return
     */
    @PostMapping("/uploadImg")
    public Response uploadImg(@RequestParam("id") Integer id, @RequestParam("file") MultipartFile[] files) {
        if(!PermissionUtil.permissionCheck(MyHandlerInterceptor.getUid(), PermissionUtil.COURSE_INFO_EDIT, id)) {
            return Response.error(ResultCode.NO_PERMISSION);
        }
        boolean contain = false;
        for (MultipartFile file : files) {
            String fileName = file.getOriginalFilename();
            String suffixName = fileName.substring(fileName.lastIndexOf("."));
            for (int j = 0; j < SUFFIX.length - 3; j++) {
                if (SUFFIX[j].equals(suffixName)) {
                    contain = true;
                    break;
                }
            }
            if (!contain) {
                throw new CustomException(ResultCode.FILE_ERROR);
            }
        }
        Response response = FileUtil.UploadFile(files, FileUtil.FILE_PATH + FileUtil.COURSE + id + "/");
        String url = (String) ((Map) response.get("data")).get("url");
        Course course = new Course();
        course.setId(id);
        course.setImgUrl(url);
        if(this.courseService.updateById(course)) {
            Course tmp = CourseCache.courseMap.get(course.getId());
            tmp.setImgUrl(course.getImgUrl());
            CourseCache.courseMap.put(tmp.getId(),tmp);
            return Response.ok();
        } else {
            return Response.error(ResultCode.COURSE_DATA_REMOVE_PERMISSION_ERROR);
        }
    }

    /**
     * 上传课程资料图片
     * @param courseId
     * @param files
     * @return
     */
    @PostMapping("/uploadDataImg")
    @PermissionCheck(PermissionUtil.COURSE_INFO_EDIT)
    public Response uploadDataImg(@RequestParam("courseId") Integer courseId, @RequestParam("file") MultipartFile[] files){
        if(!CourseCache.courseMap.containsKey(courseId)){
            return Response.error(ResultCode.PARAMETER_ERROR);
        }
        boolean contain = false;
        for (MultipartFile file : files) {
            String fileName = file.getOriginalFilename();
            String suffixName = fileName.substring(fileName.lastIndexOf("."));
            for (int i = 0; i < 6; i++) {
                if (SUFFIX[i].equals(suffixName)) {
                    contain = true;
                    break;
                }
            }
            if (!contain) {
                throw new CustomException(ResultCode.FILE_ERROR);
            }
        }
        Response response =  FileUtil.UploadFile(files,FileUtil.FILE_PATH+FileUtil.DATABASE+courseId+"/");
        if(response.get("data") == null){
            return Response.error(ResultCode.FILE_UPLOAD_ERROR);
        }
        String url = (String) ((Map) response.get("data")).get("url");
        if(courseService.updateDataImg(courseId,url)){
            Course tmp = CourseCache.courseMap.get(courseId);
            tmp.setDataImg(url);
            CourseCache.courseMap.put(tmp.getId(),tmp);
            return Response.ok();
        }else {
            return Response.error(ResultCode.UPDATE_MESSAGE_ERROR);
        }
    }
    
    /**
     * 根据课程 id 获取助教
     * @param id 课程 id
     * @return 助教
     */
    @PostMapping("/getAssistants")
    public Response getAssistants(@RequestParam("id") Integer id) {
        List<AssistantResponseVo> result = this.courseService.getAssistants(id);
        if(!result.isEmpty()) {
            return Response.ok(result);
        } else {
            return Response.error(ResultCode.LOG_NOT_EXIST);
        }
    }

    /**
     * 添加前置课程
     * @param preCourseInsert
     * @return
     */
    @PostMapping("/insertPreCourse")
    @PermissionCheck(PermissionUtil.COURSE_INFO_EDIT)
    public Response insertPreCourse(@Valid @RequestBody PreCourseInsert preCourseInsert){
        return preCourseService.insertPreCourse(preCourseInsert);
    }

    /**
     * 获取前置课程
     * @param map
     * @return
     */
    @PostMapping("/getPreCourse")
    public Response getPreCourse(@Valid @RequestBody Map<String,Integer> map){
        Integer courseId = map.get("courseId");
        return preCourseService.getPreCourse(courseId);
    }

    /**
     * 学生添加或者更新前置课程分数
     * @param scoreInsert
     * @return
     */
    @PostMapping("/updatePreCourseScore")
    public Response updatePreCourseScore(@Valid @RequestBody ScoreInsert scoreInsert){
        return preCourseScoreService.insertOrUpdatePreCourseScore(scoreInsert);
    }

    /**
     * 学生获取自己前置课程分数
     * @param map
     * @return
     */
    @PostMapping("/getPreCourseScore")
    public Response getPreCourseScore(@RequestBody Map<String,Integer> map){
        Integer courseId = map.get("courseId");
        if(courseId == null || !CourseCache.courseMap.containsKey(courseId)){
            return Response.error(ResultCode.PARAMETER_ERROR);
        }
        return preCourseScoreService.getPreCourseScore(courseId);
    }

    /**
     * 教师修改学生的前置课程分数
     */
    @PostMapping("/updateStuPreCourseScore")
    public Response updateStuPreCourseScore(@RequestBody Map<String,String> map){
        if(UserCache.userMap.get(MyHandlerInterceptor.getUid()).getType() != 1) {
            return Response.error(ResultCode.NO_PERMISSION);
        }
        Integer id,score;
        try{
            id = Integer.parseInt(map.get("id"));
            score = Integer.parseInt(map.get("score"));
        }catch (Exception e){
            return Response.error(ResultCode.PARAMETER_ERROR);
        }
        return preCourseScoreService.updateStuPreCourseScore(id,score);
    }

    /**
     * 教师获取学生的前置课程分数
     */
    @PostMapping("/getStuPreScore")
    public Response getStuPreScore(@RequestBody Map<String,String> map){
        if(UserCache.userMap.get(MyHandlerInterceptor.getUid()).getType() != 1) {
            return Response.error(ResultCode.NO_PERMISSION);
        }
        Integer studentId,courseId;
        try{
            studentId = Integer.parseInt(map.get("studentId"));
            courseId = Integer.parseInt(map.get("courseId"));
        }catch (Exception e){
            return Response.error(ResultCode.PARAMETER_ERROR);
        }
        return preCourseScoreService.getStuPreCourseScore(studentId,courseId);
    }

}
